//axios请求封装
import axios from "axios"; //引入axios
import type { AxiosRequestConfig, Method } from "axios"; //axios类型
import NProgress from "nprogress"; //axios请求时展现nprogress进度条
import JSONbig from "json-bigint"; //处理长精度数据
import { ElNotification } from "element-plus"; //处理导航信息
import router from "../router/index";
import { useAdminInfo } from "@/store/adminInfo";
import qs from "qs";
import { ElMessage, ElMessageBox } from "element-plus";
import { Local, Session } from "@/utils/storage";
import { ADMIN_INFO, BA_ACCOUNT } from "@/store/constant/cacheKey";
import { useRegion } from "@/store/backend/SysM/region";
import { useAccess } from "@/store/backend/DeviceM/access";
import { useOverView } from "@/store/backend/EquipM/overView";
import { useNavTabs } from "@/store/navTabs";
import { useBigBoardB } from "@/store/backend/BigBoard/bigBoard2";
import { tansParams, blobValidate } from "@/utils/common";
import { saveAs } from "file-saver";
import errorCode from "@/utils/errorCode";

const controller = new AbortController();

const judgArr = (params: any) => {
  let res = false;
  if (params instanceof Object) {
    Object.keys(params).forEach((key) => {
      if (Array.isArray(params[key])) {
        res = true;
      }
    });
  }
  return res;
};

const pendingMap = new Map();
axios.defaults.baseURL = "/apistwo";
let tConfig = true;
//请求拦截
axios.interceptors.request.use(
  async (config) => {
    if (config.url !== "/system/eqattribute/nowlistbylist") {
      NProgress.start(); //进度条开始
    }
    //removePending(config); //删除重复的请求
    //addPending(config); //储存每个请求唯一值, 也就是cancel()方法, 用于取消请求
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);
//响应拦截
axios.interceptors.response.use(
  (response) => {
    NProgress.done(); //进度条结束
    //removePending(response.config); //删除重复
    return response;
  },
  (error) => {
    //error.config && removePending(error.config); //删除重复
    httpErrorStatusHandle(error);
    return Promise.reject(error);
  }
);
// callback后期类型
type CB = (res: any) => {};
//http请求接口
export const http = ({
  url = "",
  data = {}, //请求传递的参数
  method = "", //使用的方法
  callback = "", //回调的结果
  type = "", //header类型
  responseType = "", //返回值类型
  ...other //other.base判断是否需要bath认证 .noToken表示不许要token
}: {
  url: string;
  data: object;
  method: string;
  callback: string | CB;
  type: string;
  responseType: string;
  other: any;
}) => {
  return new Promise((resolve, reject) => {
    if (method === "get") {
      axios({
        method,
        url,
        params: data,
        transformResponse: [
          function (data) {
            // 对 data 进行任意转换处理
            try {
              // 如果转换成功则返回转换的数据结果
              return JSON.parse(JSON.stringify(JSONbig.parse(data)));
            } catch (err) {
              // 如果转换失败，则包装为统一数据格式并返回
              return {
                data,
              };
            }
          },
        ],
        headers: {
          "Content-Type":
            type === "json"
              ? "application/json;application/octet-stream"
              : "application/x-www-form-urlencoded",
          Authorization: url === "/captchaImage" ? "" : getToken(),
        },
        responseType: responseType as any,
        ...other,
      }).then((res) => {
        //判断后端返回的状态码
        if (res.status >= 200 && res.status < 300) {
          if (res.data.code === 215 || res.data.code === 223) {
          } else if (res.data.code === 200) {
            resolve(res.data);
            tConfig = true;
          } else if (res.data.code === 401 && tConfig) {
            const adminInfo = useAdminInfo();
            tConfig = false;
            //401token过期跳转到首页
            ElMessageBox.confirm("登录已过期请重新登录", "Warning", {
              confirmButtonText: "确定",
              cancelButtonText: "取消",
              type: "warning",
            })
              .then(() => {
                const region = useRegion();
                const access = useAccess();
                const overview = useOverView();
                const navTabs = useNavTabs();
                const bigBoardB = useBigBoardB();
                reject(res);
                Local.remove(ADMIN_INFO);
                adminInfo.$reset(); //重置
                region.regionIds = []; //用户区域id 还原默认值
                access.companyid = null; //用户的企业id 还原默认值
                access.switch = false; //设备启停 还原默认值
                overview.main = false; //总览头部展示与否 还原默认值
                navTabs.state.tabsViewRoutes = []; //清除路由菜单缓存
                bigBoardB.markers = [];
                router.push({ name: "Home" });
              })
              .catch(() => {
                reject(res);
                router.push({ name: "Home" });
                ElMessage({
                  type: "info",
                  message: "登录已过期 不能进行操作",
                });
              });
          } else if (res.data.code === 403) {
            //403  无相应权限
            // ElNotification({
            //   type: "warning",
            //   message: res.data.msg,
            // });
            reject(res);
          } else if (res.data.code === 401 && !tConfig) {
          } else if (res.data.code === 500) {
            console.log("url", url);
            reject(res);
            if (
              url !== "/system/equipment/listBytree" &&
              url !== "/system/equipment/undefined" &&
              url !== "/system/warning"
            ) {
              ElNotification({
                type: "error",
                dangerouslyUseHTMLString: true,
                message: res.data.msg,
              });
            }
          } else {
            reject(res);
            console.log("报错url", url);
            if (url !== "/system/equipment/listBytree") {
              ElNotification({
                type: "error",
                dangerouslyUseHTMLString: true,
                message: res.data.msg,
              });
            } else {
              // ElNotification({
              //   type: "error",
              //   message: "你所拥有地区已超出限制请联系管理人员",
              // });
            }
          }
        }
      });
      return;
    } else {
      axios({
        method,
        url,
        data: data,
        transformResponse: [
          function (data) {
            // 对 data 进行任意转换处理
            try {
              // 如果转换成功则返回转换的数据结果
              return JSON.parse(JSON.stringify(JSONbig.parse(data)));
            } catch (err) {
              // 如果转换失败，则包装为统一数据格式并返回
              return {
                data,
              };
            }
          },
        ],
        headers: {
          "Content-Type":
            type === "json"
              ? "application/json;application/octet-stream"
              : "application/x-www-form-urlencoded",
          Authorization: getToken(), //other.base? "Basic " + window.btoa("client-admin" + ":" + "123456"):getToken()
        },
        responseType: responseType as any,
        timeout: 70000,
        ...other,
      }).then((res) => {
        //下载blob文件流数据
        if (responseType === "blob") {
          const blob = new Blob([res.data.data], { type: "application/zip" });
          const filename = res.headers["content-disposition"];
          const downloadElement = document.createElement("a");
          const href = window.URL.createObjectURL(blob); //创建下载的链接
          downloadElement.href = href;
          [downloadElement.download] = [filename!.split("=")[1]]; //filename非空断言 意为排除null和undfined
          document.body.appendChild(downloadElement);
          downloadElement.click(); //点击下载
          document.body.removeChild(downloadElement); //下载完成移除元素
          window.URL.revokeObjectURL(href); //释放blob对象
          resolve(res);
          return;
        }
        //判断状态码
        if (res.status >= 200 && res.status < 300) {
          //215 为token过期或为空字符串,需要重新获取token
          //223 为用户未注册，需要走登录逻辑
          if (res.data.code === 215 || res.data.code === 223) {
          } else if (res.data.code === 200) {
            //返回成功200
            resolve(res);
            tConfig = true;
          } else if (res.data.code === 401 && tConfig) {
            const adminInfo = useAdminInfo();
            tConfig = false;
            //401token过期跳转到首页
            ElMessageBox.confirm("登录已过期请重新登录", "Warning", {
              confirmButtonText: "确定",
              cancelButtonText: "取消",
              type: "warning",
            })
              .then(() => {
                const region = useRegion();
                const access = useAccess();
                const overview = useOverView();
                const navTabs = useNavTabs();
                const bigBoardB = useBigBoardB();
                reject(res);
                Local.remove(ADMIN_INFO);
                adminInfo.$reset(); //重置
                region.regionIds = []; //用户区域id 还原默认值
                access.companyid = null; //用户的企业id 还原默认值
                access.switch = false; //设备启停 还原默认值
                overview.main = false; //总览头部展示与否 还原默认值
                navTabs.state.tabsViewRoutes = []; //清除路由菜单缓存
                bigBoardB.markers = [];
                router.push({ name: "Home" });
              })
              .catch(() => {
                reject(res);
                router.push({ name: "Home" });
                ElMessage({
                  type: "info",
                  message: "登录已过期 不能进行操作",
                });
              });
          } else if (res.data.code === 403) {
            // ElNotification({
            //   type: "warning",
            //   message: res.data.msg,
            // });
          } else if (res.data.code === 401 && !tConfig) {
          } else if (res.data.code === 500) {
            console.log("url", url);
            reject(res);
            if (
              url !== "/system/equipment/listBytree" &&
              url !== "/system/equipment/undefined" &&
              url !== "/system/warning"
            ) {
              ElNotification({
                type: "error",
                dangerouslyUseHTMLString: true,
                message: res.data.msg,
              });
            }
          } else {
            //其余的错误直接返回给reject
            reject(res);
            console.log("其余的错误直接返回给reject", res.data);

            // ElNotification({
            //   type: "error",
            //   message: res.data.msg,
            // });
          }
        } else {
          //!发生错误跳转到指定页面
          reject(res);
          ElNotification({
            type: "error",
            dangerouslyUseHTMLString: true,
            message: res.data.msg,
          });
        }
      });
    }
  });
};
type Log = {
  avatar: string;
  id: 1;
  lastlogintime: string;
  nickname: string;
  refreshToken: string;
  super: boolean;
  token: string;
  username: string;
};
//获取token
export const getToken = (): string => {
  const token =
    JSON.parse(localStorage.getItem("adminInfo") as any)?.token || "";
  return token;
};
//获取refreshToken
export const getRefreshToken = (): string => {
  const refreshToken = localStorage.getItem("refreshToken") || "";
  console.log("获取的refreshtoken");
  return refreshToken;
};

//过期token重新刷新token
export const getNewToken = (url: string) => {
  return new Promise((resolve, reject) => {
    let data: refreshTokenData = {
      grantType: "admin_refresh_token",
      scope: "all",
      refreshToken: getRefreshToken(),
    };
    //刷新token
    axios({
      method: "post",
      url,
      data,
      headers: {
        "content-type": "application/json;charset=UTF-8",
        Authorization: "Basic " + window.btoa("client-admin" + ":" + "123456"),
      },
      // responseType: "text",
    })
      .then((res: any) => {
        console.log(res);
        //请求成功
        if (res.data.code === 200) {
          let { token, refreshToken, tokenType } = res.data.data;
          //将获取的token与refreshToken存储到localstorage中
          localStorage.setItem("token", tokenType + token);
          localStorage.setItem("refreshToken", refreshToken);
          resolve(res);
        } else {
          //登录中途失败
          if (res.data.code === 215 || res.data.code === 500) {
            //未注册用户跳转注册
            //获取新token失败跳转到login页面
            router.push({ path: "/login" });
          }
        }
      })
      .catch((err: any) => {
        console.log(err);
        reject(err);
        router.push({ path: "/login" });
      });
  });
};

/**
 * 处理异常
 * @param {*} error
 */
function httpErrorStatusHandle(error: any) {
  console.log("error响应拦截", error);
  if (error.response.status === 403) {
    ElNotification({
      type: "error",
      message: "请勿重复登录，使用快捷登录即可",
    });
  } else {
    // ElNotification({
    //   type: "error",
    //   message: error.message,
    // });
  }
}

// 常用的四种方法
export const _get = (
  url: string,
  data = {},
  type: string,
  responseType: string,
  other = {}
) => {
  return http({
    url,
    data,
    method: "get",
    type,
    responseType,
    callback: "",
    other,
  });
};

export const _post = (
  url: string,
  data = {},
  type: string,
  responseType: string,
  other = {}
) => {
  return http({
    url,
    data,
    method: "post",
    type,
    responseType,
    callback: "",
    other,
  });
};

export const _put = (
  url: string,
  data = {},
  type: string,
  responseType: string,
  other = {}
) => {
  return http({
    url,
    data,
    method: "put",
    type,
    responseType,
    callback: "",
    other,
  });
};

export const _delete = (
  url: string,
  data = {},
  type: string,
  responseType: string,
  other = {}
) => {
  return http({
    url,
    data,
    method: "delete",
    type,
    responseType,
    callback: "",
    other,
  });
};
//删除重复的请求
function removePending(config: AxiosRequestConfig) {
  const pendingKey = getPendingKey(config);
  if (pendingMap.has(pendingKey)) {
    const cancelToken = pendingMap.get(pendingKey);
    cancelToken(pendingKey);
    pendingMap.delete(pendingKey);
  }
}

//储存每个请求唯一值, 也就是cancel()方法, 用于取消请求
function addPending(config: AxiosRequestConfig) {
  const pendingKey = getPendingKey(config);
  config.cancelToken =
    config.cancelToken ||
    new axios.CancelToken((cancel) => {
      if (!pendingMap.has(pendingKey)) {
        pendingMap.set(pendingKey, cancel);
      }
    });
}

// 生成每个请求唯一的键
function getPendingKey(config: AxiosRequestConfig) {
  let { url, method, params, data } = config;
  if (typeof data === "string") data = JSON.parse(data); // response里面返回的config.data是个字符串对象
  return [url, method, JSON.stringify(params), JSON.stringify(data)].join("&");
}
interface anyObj {
  [key: string]: any;
}
// 重新获取token的参数类型
type refreshTokenData = {
  grantType: string;
  scope: string;
  refreshToken: string;
};

//通用下载方法
export const _download = (url: any, params: any, filename: any) => {
  return axios
    .post(url, params, {
      transformRequest: [
        (params) => {
          return tansParams(params);
        },
      ],
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        Authorization: url === "/captchaImage" ? "" : getToken(),
      },
      responseType: "blob",
    })
    .then(async (res: any) => {
      console.log("下载的文件", res.data);

      const isLogin = await blobValidate(res.data);
      if (isLogin) {
        const blob = new Blob([res.data]);
        saveAs(blob, filename);
      } else {
        const resText = await res.data.text();
        const rspObj = JSON.parse(resText);
        const errMsg =
          (errorCode as any | string)[rspObj.code] ||
          rspObj.msg ||
          errorCode["default"];
        ElMessage.error(errMsg);
      }
      // downloadLoadingInstance.close();
    })
    .catch((r) => {
      console.error(r);
      ElMessage.error("下载文件出现错误，请联系管理员！");
      // downloadLoadingInstance.close();
    });
};
//通用上传方法
export const _upload = (url: any, data: any, filename: any) => {
  console.log("通用上传方法", url);
  // if (url === "/common/upload") {
  //   axios.defaults.baseURL = "/file";
  // }
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      return axios
        .post(url, data, {
          headers: {
            "Content-Type": "multipart/form-data",
            Authorization: getToken(),
          },
        })
        .then(async (res: any) => {
          // axios.defaults.baseURL = "/apisone";
          resolve(res);
          console.log("上传的文件", res.data);
        })
        .catch((r) => {
          console.error(r);
          ElMessage.error("上传文件出现错误，请联系管理员！");
          // axios.defaults.baseURL = "/apis";
        });
    }, 500);
  });
};
